﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

#pragma once

#include "NdbPropertySchema.h"
#include "NdbTypeTraits.h"
#include "ClassId.h"

namespace gcmp
{
    class NdbIOStream;
    class NdbObject;
    class NdbClassSchemaLibrary;

    typedef std::function<gcmp::OwnerPtr<NdbObject>()> CreateNdbObjectFunction;
    /// \brief 类schema错误
    enum class SchemaError : int32_t
    {
        No = 0,                               ///< 没有错误。
        FileContainsUnrecognizedElements = 1, ///< 含有不认识的对象。比如数据定义模块未加载。
        VersionNewerThanApp = 2,              ///< 类版本比App中的高。
    };

    /// \brief 类schema定义
    class GCMP_DATABASE_EXPORT NdbClassSchema
    {
        friend class NdbClassSchemaLibrary;
        friend class NdbClassSchemaUtils;
    public:
        NdbClassSchema(void);

        NdbClassSchema(
            const ClassId & parentClassId,
            const ClassId & classId,
            const std::wstring & parentClassName,
            const std::wstring & className,
            CreateNdbObjectFunction createFunction,
            UInt64 size,
            const Guid & assemblyId,
            const std::wstring & assemblyName,
            UInt32 index
        );

        NdbClassSchema(const NdbClassSchema & another) = delete;
        NdbClassSchema(NdbClassSchema && another) = delete;
        NdbClassSchema & operator = (const NdbClassSchema & another) = delete;
        NdbClassSchema & operator = (NdbClassSchema && another) = delete;

        OwnerPtr<NdbClassSchema> Clone() const;

        bool IsValid(std::wstring * pErrorMessage) const;

        // 把属性数据加入到指定的NdbClassSchema里
        static NdbPropertySchemaType AddPropertySchema(
            NdbPropertySchemaType schemaType,
            IntOrFloatType intOrFloatType,
            IntBaseType intBaseType,
            UInt32 size,
            NdbClassSchema * pClassSchema,
            const std::wstring & name,
            const std::wstring & type,
            UInt32 offset,
            Int32 behaviorTypes
        );
    public:
        CreateNdbObjectFunction GetCreateNdbObjectFunction() const { return m_createFunc; }

        void Dump() const;
        std::wstring ToWString(bool withProperties, bool recursively) const;

        void Serialize(IIOStream & ioStream) const;

        // 反序列化：主版本2的实现。
        SchemaError Unserialize(IIOStream & ioStream, bool guarantee, std::wstring* errorMessage);

        bool Compare(const NdbClassSchema *pClassSchema) const;

        const ClassId & GetClassId() const { return m_classId; }
        const ClassId & GetParentClassId() const { return m_parentClassId; }
        bool IsBottomClass() const { return m_children.empty(); }
        FORCE_INLINE bool IsTopClass() const { return !m_parentClassId.IsValid(); }

        bool GetPropertySchema(const std::wstring& propertyName, NdbPropertySchema& out) const;
        const std::vector<NdbPropertySchema>& GetPropertySchemas() const {return m_properties;}
        void EmplaceBackPropertySchema(NdbPropertySchema && propertySchema) { m_properties.emplace_back(propertySchema); }

        NdbClassSchema* GetParentClassSchema() const { return m_parent; }
        const std::vector<NdbClassSchema*>& GetChildrenClassSchemas() const { return m_children; }

        const std::wstring& GetName() const { return m_className; }
        UInt32 GetIndex() const { return m_index; }

        // 获取类schema的当前版本号
        UInt32 GetVersion() const { return m_version; }
        void SetVersion(UInt32 version) { m_version = version; }

        const Guid & GetAssemblyId() const { return m_assemblyId; }

        const std::wstring & GetAssemblyName() const { return m_assemblyName; }

        // 是否需要序列化到文件中
        bool ShouldArchive() const { return m_shouldArchive; }
        void SetShouldArchive(bool shouldArchive) { m_shouldArchive = shouldArchive; }

        const std::vector<UInt32>& GetBottomChildrenIds() const { DBG_WARN_UNLESS(!m_bottomChildrenIds.empty(), L"这个类来自Addin?", L"GMEP", L"2016/09/23"); return m_bottomChildrenIds; }

        //判断是不是平台内建数据，如果是平台内建的返回true，否则返回false
        FORCE_INLINE Bool IsIntrinsic() const { return m_isIntrinsic; }

        void SetParentClassId(const ClassId& classId) { m_parentClassId = classId; }
        std::vector<NdbPropertySchema>& GetPropertySchemasFW() { return m_properties; }
        static void SuppressSchemaVersionWarnings(bool suppress);

        const std::pair<SchemaError, std::wstring> & GetUnserializeResult() const { return m_unserializeResult; }

        std::wstring GetClassSchemaSignature() const { return m_classId.AsWString() + StringUtil::ToWString(m_version); }

    private:
        friend class NdbClassSchemaLibraryOfCode;
        friend class NdbClassSchemaLibraryUtils;
        friend class NdbUpgradeManager;

        // 需要序列化反序列化的成员
        ClassId                        m_parentClassId;
        ClassId                        m_classId;
        std::wstring                   m_parentClassName;   //仅在文件序列化和反序列化时使用
        std::wstring                   m_className;         //仅在文件序列化和反序列化时使用
        UInt32                         m_version;
        UInt32                         m_index;
        Guid                           m_assemblyId;
        std::wstring                   m_assemblyName;
        std::vector<NdbPropertySchema> m_properties;
        Bool                           m_isIntrinsic;

        // 由初始化函数设定，但序列化反序列化无意义
        bool                           m_shouldArchive;
        CreateNdbObjectFunction        m_createFunc;
        UInt64                         m_size;

        // 需要在其它成员初始化之后或者反序列化之后计算出来的成员
        // 只在运行时有效
        std::vector<NdbClassSchema*>   m_children;          // 子类
        NdbClassSchema*                m_parent;            // 父类
        std::vector<UInt32>            m_bottomChildrenIds; // 最底层子节点在NdbSchemaManager中的索引

        // 标志是否suppress schema version related warnings
        //
        static bool                    m_bSuppressSchemaVersionWarnings;

        std::pair<SchemaError, std::wstring>   m_unserializeResult;
    };

    // 推断属性类型并加入属性schema到对应的classSceham
    template <typename T>
    NdbPropertySchemaType InferTypeAndAddPropertySchema(const T * pT, NdbClassSchema * pClassSchema, const std::wstring & name, const std::wstring & type, UInt32 offset, Int32 behaviorTypes)
    {
        DBG_WARN_AND_RETURN_UNLESS(pClassSchema, NdbPropertySchemaType::Invalid, L"pClassSchema是空？", L"GMEP", L"2020/12/16");
        return NdbClassSchema::AddPropertySchema(NdbPropertySchemaTypeTrait<T>::PropertySchemaType, NdbPropertySchemaTypeTrait<T>::IntOrFloatType, NdbPropertySchemaTypeTrait<T>::IntBaseType, sizeof(T), pClassSchema, name, type, offset, behaviorTypes);
    }
}
